﻿#define TEST
#define VERIFY

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

[assembly: CLSCompliant(true)]

namespace Chapter18
{
    using System.Runtime.InteropServices;
    using System.Reflection;
    using System.Diagnostics;

    [Cond]
    [Serializable]
    [DefaultMember("Main")]
    [DebuggerDisplay("Richter", Name = "Jeff", Target = typeof(Program))]
    partial class Program
    {
        private delegate void Feedback(int value);

        internal static void Begin(Action action, bool active = false)
        {
            if (active)
            {
                Console.WriteLine("开始演示：");
                action();
                Console.WriteLine("演示完毕：");
                Console.ReadLine();
            }
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        internal sealed class OSVERSIONINFO
        {
            public int OSVersionInfoSize = 0;
            public int MajorVersion = 0;
            public int MinorVersion = 0;
            public int BuildNumber = 0;
            public int PlatformId = 0;

            public OSVERSIONINFO()
            {
                OSVersionInfoSize = (int)Marshal.SizeOf(this);
            }

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string CSDVersion = null;
        }

        internal sealed class MyClass
        {
            [DllImport("Kernel32", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern bool GetVersionEx([In, Out]OSVERSIONINFO ver);
        }

        [AttributeUsage(AttributeTargets.Enum, Inherited = false)]
        internal class FlagsAttribute : Attribute
        {
            public FlagsAttribute()
            {

            }
        }

        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
        internal class TastAttribute : Attribute { }

        [Tast]
        [Serializable]
        internal class BaseType
        {
            [Tast]
            protected virtual void DoSomething() { }
        }

        internal class DerivedType : BaseType
        {
            protected override void DoSomething() { }
        }

        internal enum Color
        {
            Red
        }

        [AttributeUsage(AttributeTargets.All)]
        internal sealed class SomeAttribute : Attribute
        {
            public SomeAttribute(string name, object o, Type[] types)
            {

            }
        }

        [Some("Jeff", Color.Red, new Type[] { typeof(Math), typeof(Console) })]
        internal sealed class SomeType
        {

        }

        [Conditional("Debug")]
        [Conditional("Release")]
        public void DoSomething() { }

        internal static void C04()
        {
            ShowAttributes(typeof(Program));
            MemberInfo[] members = typeof(Program).FindMembers(
                MemberTypes.Constructor | MemberTypes.Method,
                BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static,
                Type.FilterName,
                "*");
            foreach (MemberInfo member in members)
            {
                ShowAttributes(member);
            }
        }

        private static void ShowAttributes(MemberInfo attributeTarget)
        {
            Attribute[] attributes = Attribute.GetCustomAttributes(attributeTarget);
            Console.WriteLine("Attribute applied to {0}: {1}", attributeTarget.Name, (attributes.Length == 0 ? "None" : string.Empty));
            foreach (Attribute attribute in attributes)
            {
                Console.WriteLine("  {0}", attribute.GetType().ToString());
                if (attribute is DefaultMemberAttribute)
                    Console.WriteLine("  MemberName={0}", ((DefaultMemberAttribute)attribute).MemberName);
                if (attribute is ConditionalAttribute)
                    Console.WriteLine("  ConditionString={0}", ((ConditionalAttribute)attribute).ConditionString);
                if (attribute is CLSCompliantAttribute)
                    Console.WriteLine("  MemberName={0}", ((CLSCompliantAttribute)attribute).IsCompliant);
                var dda = attribute as DebuggerDisplayAttribute;
                if (dda != null)
                    Console.WriteLine("  Value={0}, Name={1}, Target={2}", dda.Value, dda.Name, dda.Target);
            }
            Console.WriteLine();
        }

        private static void ShowAttributes2(MemberInfo attributeTarget)
        {
            IList<CustomAttributeData> attributes = CustomAttributeData.GetCustomAttributes(attributeTarget);
            Console.WriteLine("Attribute applied to {0}: {1}", attributeTarget.Name, (attributes.Count == 0 ? "None" : string.Empty));
            foreach (CustomAttributeData attribute in attributes)
            {
                Type t = attribute.Constructor.DeclaringType;
                Console.WriteLine("  {0}", t.ToString());
                Console.WriteLine("    Construcctro called={0}", attribute.Constructor);
                IList<CustomAttributeTypedArgument> posArgs = attribute.ConstructorArguments;
                Console.WriteLine("    Positional arguments passed to constructor: {0}", (posArgs.Count == 0) ? " None" : string.Empty);
                foreach (CustomAttributeTypedArgument pa in posArgs)
                {
                    Console.WriteLine("    Type={0}, Value={1}", pa.ArgumentType, pa.Value);
                }
                IList<CustomAttributeNamedArgument> nameArgs = attribute.NamedArguments;
                Console.WriteLine("    Named arguments set after construction: {0}", (nameArgs.Count == 0) ? " None" : string.Empty);
                foreach (CustomAttributeNamedArgument na in nameArgs)
                {
                    Console.WriteLine("    Type={0}, Value={1}", na.TypedValue.ArgumentType, na.TypedValue.Value);
                }
                Console.WriteLine();
            }
            Console.WriteLine();
        }

        [Flags]
        internal enum Accounts
        {
            Saving = 0x0001,
            Checking = 0x0002,
            Brokerage = 0x0004
        }

        [AttributeUsage(AttributeTargets.Class)]
        internal sealed class AccountsAttribute : Attribute
        {
            private Accounts accounts;

            public AccountsAttribute(Accounts accounts)
            {
                this.accounts = accounts;
            }

            public override bool Match(object obj)
            {
                //if (!base.Match(obj)) return false;
                if (obj == null) return false;
                if (this.GetType() != obj.GetType()) return false;
                AccountsAttribute other = (AccountsAttribute)obj;
                if ((other.accounts & accounts) != accounts) return false;
                return true;
            }

            public override bool Equals(object obj)
            {
                //if (!base.Equals(obj)) return false;
                if (obj == null) return false;
                if (this.GetType() != obj.GetType()) return false;
                AccountsAttribute other = (AccountsAttribute)obj;
                if (other.accounts != accounts) return false;
                return true;
            }

            public override int GetHashCode()
            {
                return (int)accounts;
            }
        }

        [Accounts(Accounts.Saving)]
        internal sealed class ChildAccount { }

        [Accounts(Accounts.Saving | Accounts.Checking | Accounts.Brokerage)]
        internal sealed class AdultAccount { }

        private static void CanWriteCheck(object obj)
        {
            Attribute checking = new AccountsAttribute(Accounts.Checking);
            Attribute validAccounts = Attribute.GetCustomAttribute(obj.GetType(), typeof(AccountsAttribute), false);
            if ((validAccounts) != null && checking.Match(validAccounts))
                Console.WriteLine("{0} tpyes can write checks.", obj.GetType());
            else
                Console.WriteLine("{0} types can NOT write checks.", obj.GetType());
        }

        internal static void C05()
        {
            CanWriteCheck(new ChildAccount());
            CanWriteCheck(new AdultAccount());
            CanWriteCheck(new Program());
        }

        internal static void C06()
        {
            ShowAttributes2(typeof(Program));
            MemberInfo[] members = typeof(Program).FindMembers(
                MemberTypes.Constructor | MemberTypes.Method,
                BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static,
                Type.FilterName,
                "*");
            foreach (MemberInfo member in members)
            {
                ShowAttributes(member);
            }
        }

        [Conditional("TEST")]
        [Conditional("VERIFY")]
        internal sealed class CondAttribute : Attribute
        {

        }

        internal static void C07()
        {
            Console.WriteLine("CondAttritue is {0}applied to Program type.", Attribute.IsDefined(typeof(Program), typeof(CondAttribute)) ? "" : "not ");
        }
    }
}
